//
//$Id: app.cpp 687 2011-03-13 12:21:29Z andrew.tsyganov $
#include "stdafx.h"
#include "include/app.h"
#include "include/types.h"
#include "include/fa_utils.h"
#include "include/generate.h"
#include "include/re2fa.h"
#include "include/utils.h"

#if defined(_WIN32)
#include "include/dirent.h"
#else
#include <dirent.h>
#endif

using namespace std;
using namespace app;

int App::canonize(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: canonize input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            FA fa;

            if (GetFA(file, fa))
            {
                FA dfa, rdfa, mdfa;
                vector<Subset> vs_fa, vs_dfa;
                Determinize(fa, dfa, vs_fa);
                Reverse(dfa, rdfa);
                MinimizeHopcroft(dfa, rdfa, mdfa, vs_dfa);
                mdfa.save_XML(CreatePath(dir2, name + "_can." + ext));
            }
        }
    }

    closedir(dp);

    return 0;
}

int App::codeterminize(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: codeterminize input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            FA fa;

            if (GetFA(file, fa))
            {
                FA rfa, drfa, rdrfa;
                vector<Subset> vs;
                Reverse(fa, rfa);
                Determinize(rfa, drfa, vs);
                Reverse(drfa, rdrfa);
                rdrfa.save_XML(CreatePath(dir2, name + "_codet." + ext));
            }
        }
    }

    closedir(dp);

    return 0;
}

int App::determinize(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: determinize input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            FA fa;

            if (GetFA(file, fa))
            {
                FA dfa;
                vector<Subset> vs;
                Determinize(fa, dfa, vs);
                dfa.save_XML(CreatePath(dir2, name + "_det." + ext));
            }
        }
    }

    closedir(dp);

    return 0;
}

int App::equivalent(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: equivalent input_file1.xml input_file2.xml" << endl;
        return 1;
    }

    string file1 = argv[2];
    string file2 = argv[3];
    FA fa1, fa2;

    if (!GetFA(file1, fa1) || !GetFA(file2, fa2))
    {
        cout << "Load error!" << endl;
        return 1;
    }

    cout << ( AreEquivalentFAs(fa1, fa2) ? "true" : "false" ) << endl;

    return 0;
}

int App::export_(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: export input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            if (HasFANode(file))
            {
                FA fa;

                if (fa.load_XML(CreatePath(dir, fname)))
                {
                    fa.save_TXT(CreatePath(dir2, name + ".txt"));
                    fa.save_LaTeX(CreatePath(dir2, name + ".tex"));
                    fa.save_GAP(CreatePath(dir2, name + ".gap"));
                    fa.save_GV(CreatePath(dir2, name + ".gv"));
                }
            }
        }
    }

    closedir(dp);

    return 0;
}

int App::generate(int argc, char* argv[]) const
{
    if (argc < 3)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: generate output_dir [options.xml]" << endl;
        return 1;
    }

    Generate gen;
    if (argc >= 4)
    {
        string file = argv[3];
        if (!gen.load_XML(file))
        {
            cout << "Error reading options file! Proceed with default options." << endl;
        }
    }

    string dir = argv[2];
    gen.run(dir);

    return 0;
}

int App::isomorphic(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: isomorphic input_file1.xml input_file2.xml" << endl;
        return 1;
    }

    string file1 = argv[2];
    string file2 = argv[3];
    FA fa1, fa2;

    if (!fa1.load_XML(file1) || !fa2.load_XML(file2))
    {
        cout << "Automata load error!" << endl;
        return 1;
    }

    if (!fa1.is_Deterministic() || !fa2.is_Deterministic())
    {
        cout << "Automata should be deterministic!" << endl;
        return 1;
    }

    if (!fa1.is_Dense() || !fa2.is_Dense())
    {
        cout << "Automata should be dense!" << endl;
        return 1;
    }

    vector<u_t> vu;
    cout << ( AreIsomorphicDFAs(fa1, fa2, vu) ? "true" : "false" ) << endl;

    return 0;
}

int App::re2fa(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: re2fa input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            if (HasRENode(file))
            {
                RE re;

                if (re.load_XML(CreatePath(dir, fname)))
                {
                    FA fa;
                    REToFA(re, fa);
                    fa.save_XML(CreatePath(dir2, name + "_fa." + ext));
                }
            }
        }
    }

    closedir(dp);

    return 0;
}



int App::reverse(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: reverse input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            if (HasFANode(file))
            {
                FA fa;

                if (fa.load_XML(CreatePath(dir, fname)))
                {
                    FA rfa;
                    Reverse(fa, rfa);
                    rfa.save_XML(CreatePath(dir2, name + "_rev." + ext));
                }
            }
        }
    }

    closedir(dp);

    return 0;
}


//EOF!

